#!/bin/bash
#set -x
######################################################
# ref :
#  静的解析手順: https://confluence.tmc-stargate.com/pages/viewpage.action?pageId=51681148
#  CodeQL解析実行手順【ローカル環境】: https://confluence.tmc-stargate.com/pages/viewpage.action?pageId=51682796
#  code rule: https://confluence.tmc-stargate.com/pages/viewpage.action?pageId=37148697
######################################################
######################################################
# Common variables
######################################################
WORK_PATH=$(readlink -f ${0} | xargs dirname)
script_name=$(basename $0)
cfg_file=${WORK_PATH}/.${script_name%\.*}.conf
lock_file="${WORK_PATH}/.${script_name%\.*}.lock"
log_path="${WORK_PATH}/log/$(date +%Y%m%d)"
log_backup_path="${WORK_PATH}/backup/log"
log_backup_day_ago=$(date -d "7 day ago" +%Y%m%d)
log="${log_path}/${script_name%\.*}_$(date +%Y%m%d%H%M%S).log"
user_uid=$(id -u)
user_gid=$(id -g)

# sdk and tool path
sdk_path="${WORK_PATH}"
sdk_folder="arene-ivi-sdk"
tool_path="${WORK_PATH}"
tool_query_folder="arene-ivi-infra-code-scanning-cpp-query"
tool_integ_folder="arene-ivi-misc-integ-integrator"
tool_ts_query_folder="codeql-ts-query"

# input and output path
input_path="${WORK_PATH}/input"
output_path="${WORK_PATH}/output"
output_expiration_time=$(date -d "7 day ago" +%Y%m%d%H%M%S)

# backup
backup_expiration_time=$(date -d "30 day ago" +%Y%m%d)
backup_path="${WORK_PATH}/backup/$(date +%Y%m%d)"
backup_sdk_path="${backup_path}/sdk"
backup_codeql_path="${backup_path}/codeql"


######################################################
# Common function
######################################################
function start_execute
{
  if [[ -e ${lock_file} ]]; then
    echo "[ERR ] Others are using the current environment."
    exit 1
  else
    # create lock file
    touch ${lock_file}
    # create log directory
    if [[ ! -e ${log_path} ]]; then
      mkdir -p ${log_path}
    fi
    # create output path
    if [[ ! -e ${output_path} ]];then
      mkdir -p ${output_path}
    fi
    # create backup path
    if [[ ! -e ${backup_path} ]];then
      mkdir -p ${backup_path}
    fi
  fi
}
function backup_manager
{
  # backup manager
  echo "[INFO] Delete expired backup data."  >> ${log}
  pushd $(dirname ${backup_path})   >> ${log}
  {
    for dir_name in $(ls .) ; do 
      if [[ -d ${dir_name} ]] && 
         [[ ${dir_name} != log ]] &&
         [[ ${dir_name} -lt ${backup_expiration_time} ]]; then
        echo "[INFO] Command: rm -fr ${dir_name}"   >> ${log}
        rm -fr ${dir_name}          >> ${log} 2>&1
      fi
    done
  }
  popd  >> ${log} # $(dirname ${backup_path}) 
}
function finish
{
  # delete lock file.
  if [[ -e ${lock_file} ]]; then
    rm -fr ${lock_file}
  fi
  # clean ouput path
  echo "[INFO] Clean ouput path." >> ${log}
  pushd ${output_path} >> ${log}
  {
    if [[ -d ./output_codeql_analysis ]]; then
      for dir_name in $(ls ./output_codeql_analysis); do 
        dir_date=${dir_name##*_}
        if [[ -d ./output_codeql_analysis/${dir_name} ]] && 
          [[ ${dir_date} -lt ${output_expiration_time} ]]; then
          rm -fr ./output_codeql_analysis/${dir_name}
        fi
      done
    fi
  }
  popd  >> ${log} # ${output_path}/output_codeql_analysis
  # backup log
  echo "[INFO] Backup log file." >> ${log}
  pushd $(dirname ${log_path})   >> ${log}
  {
    for dir_name in $(ls .) ; do 
      if [[ -d ${dir_name} && ${dir_name} -lt ${log_backup_day_ago} ]]; then
          echo "tar -zcf ${dir_name}.tar.gz ${dir_name} --remove-files"       >> ${log}
          tar -zcf ${dir_name}.tar.gz ${dir_name} --remove-files              >> ${log} 2>&1
          if [[ ! -e ${log_backup_path} ]];then
            mkdir -p ${log_backup_path}
          fi
          mv ${dir_name}.tar.gz ${log_backup_path}
      fi
    done
  }
  popd  >> ${log} # $(dirname ${log_path})
  # backup manager
  backup_manager
  # Reset all permissions in the workspace
  local docker_tool_path=$(echo /workdir/${tool_path} | sed "s@/${WORK_PATH}@@g")
  local docker_input_path=$(echo /workdir/${input_path} | sed "s@/${WORK_PATH}@@g")
  local docker_output_path=$(echo /workdir/${output_path} | sed "s@/${WORK_PATH}@@g")
  local docker_log_path=$(echo /workdir/${log_path} | sed "s@/${WORK_PATH}@@g")
  local docker_backup_path=$(echo /workdir/${backup_path} | sed "s@/${WORK_PATH}@@g")
  nohup docker run --rm -v ~:/home/hosthome:ro -v ${WORK_PATH}:/workdir --name poky-$(id -un)-arene_codeql_exit \
  --workdir=/workdir ${CODEQL_DOCKER_IMAGE_REPOSITORY}:${CODEQL_DOCKER_IMAGE_TAG} \
    bash -c "echo 'Reset all permissions in the workspace'; \
      chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_query_folder}; \
      chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_integ_folder}; \
      chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_ts_query_folder}; \
      chown -R ${user_uid}:${user_gid} ${docker_input_path}; \
      chown -R ${user_uid}:${user_gid} ${docker_output_path}; \
      chown -R ${user_uid}:${user_gid} ${docker_log_path}; \
      chown -R ${user_uid}:${user_gid} ${docker_backup_path}; \
      rm -fr /workdir/venv; \
      exit" >> ${log} 2>&1 &
  exit 0
}
function on_ctrl_c
{
  echo ""
  echo "[INFO] Force quit the application by control + c." | tee -a ${log}
  finish
}
function on_abnormal_exit()
{
  echo ""
  echo "[ERR ] The program exited abnormally." | tee -a ${log}
  finish
}
######################################################
# Git clone and update function
#
# @function   git_clone_update
# @param      1:git_repo_url
# @param      2:git_repo_name
# @param      3:git_repo_branch
# @param      4:git_repo_branch_commitid
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function git_clone_update
{
  local git_repo_url=$1
  local git_repo_name=$2
  local git_repo_branch=$3
  local git_repo_branch_commitid=$4
  echo "------------------------------------------------------"               >> ${log}
  echo "[INFO] Start update ${git_repo_name} from ${git_repo_url}"            >> ${log}

  if [[ ${git_repo_url} != "" ]] && [[ ${git_repo_name} != "" ]] && [[ ${git_repo_branch} != "" ]]; then
    # git pull
    if [[ -e ${git_repo_name}/.git ]] ;then
      pushd ${git_repo_name}  >> ${log}
      {
        # reset branch
        git reset --hard HEAD    >> ${log} 2>&1
        git clean -df            >> ${log} 2>&1
        if [[ $? -ne 0 ]]; then
          echo "[ERR ] Failed to git clean branch." >> ${log}
          return 1
        fi

        # switch default branch
        local default_branch=$(git branch -r --points-at refs/remotes/origin/HEAD | grep '\->' | cut -d' ' -f5 | cut -d/ -f2)
        if [[ $(git rev-parse --abbrev-ref HEAD) != "${default_branch}" ]]; then
          git switch ${default_branch}    >> ${log} 2>&1
          if [[ $? -ne 0 ]]; then
            echo "[ERR ] line:${LINENO} Failed to switch default branch =>${default_branch}" >> ${log}
            return 1
          fi
        fi

        # delete other local branch
        git branch -D $(git branch -l |grep -v ${default_branch})    >> ${log} 2>&1
        # sync remote branch name
        git remote prune origin                                      >> ${log} 2>&1
        
        # update all branch
        git pull     >> ${log} 2>&1
        if [[ $? -ne 0 ]]; then
          echo "[ERR ] line:${LINENO} Failed to git pull branch." >> ${log}
          return 1
        fi
      }
      popd >> ${log}
      # git clone
    else
      # clone repository
      rm -fr ${git_repo_name}
      echo "Cloning into ${git_repo_name} ..."    >> ${log}
      git clone --progress ${git_repo_url} ${git_repo_name} 2> ${log_path}/.git_progress.log 1>> ${log}
      if [[ $? -ne 0 ]]; then
          echo "[ERR ] line:${LINENO} Failed to git clone repo. repo_url=>${repo_url}"   >> ${log}
          return 1
      fi
    fi
    pushd ${git_repo_name}  >> ${log}
    {
      # switch branche
      if [[ $(git rev-parse --abbrev-ref HEAD) != "${git_repo_branch}" ]]; then
        git checkout ${git_repo_branch}    >> ${log} 2>&1
        if [[ $? -ne 0 ]]; then
          echo "[ERR ] line:${LINENO} Failed to git checkout branch. branch=>${git_repo_branch}" >> ${log}
          return 1
        fi
      fi

      # reset commit id
      if [[ ${git_repo_branch_commitid} != "" ]];then
        echo "[INFO] Exec command=>$ git reset --hard ${git_repo_branch_commitid}"
        git reset --hard ${git_repo_branch_commitid}
        if [[ $? -ne 0 ]]; then
          echo "[ERR ] line:${LINENO} Failed to git reset --hard ${git_repo_branch_commitid}" >> ${log}
          return 1
        fi
      fi
    }
    popd >> ${log}
  else
    echo "[ERR ] line:${LINENO} Failed to update ${git_repo_name}:${git_repo_branch} from ${git_repo_url}"   >> ${log}
    echo "------------------------------------------------------"               >> ${log}
    return 1
  fi

  echo "[INFO] Successfully update ${git_repo_name} from ${git_repo_url}"     >> ${log}
  echo "------------------------------------------------------"               >> ${log}
  echo ""                                                                     >> ${log}
  return 0
}
######################################################
# Git add and update submodule function
#
# @function   git_submodule_update
# @param      1:git_parent_repo_name
# @param      2:git_sub_repo_url
# @param      3:git_sub_repo_name
# @param      4:git_sub_repo_branch
#
# @ return 
#             0:Success
#             1:Failure
######################################################
function git_submodule_update
{
  local git_parent_repo_name=$1
  local git_sub_repo_url=$2
  local git_sub_repo_name=$3
  local git_sub_repo_branch=$4
  pushd ${git_parent_repo_name}  >> ${log}
  {
    echo "Add and update submodule ${git_sub_repo_name} from ${git_sub_repo_url}" >> ${log}
    git submodule status ${git_sub_repo_name} >> ${log} 2>&1
    if [[ $? -ne 0 ]];then
      git submodule add -b ${git_sub_repo_branch} --force ${git_sub_repo_url} ${git_sub_repo_name} >> ${log} 2>&1
      if [[ $? -ne 0 ]]; then
          echo "[ERR ] line:${LINENO} Failed to git submodule add -b ${git_sub_repo_branch} --force ${git_sub_repo_url} ${git_sub_repo_name}"   >> ${log}
          return 1
      fi
    fi

    git submodule update --remote ${git_sub_repo_name} >> ${log} 2>&1
    if [[ $? -ne 0 ]]; then
        echo "[ERR ] line:${LINENO} Failed to git submodule update --remote ${git_sub_repo_name}"   >> ${log}
        return 1
    fi
  }
  popd >> ${log} # ${git_parent_repo_name}
  return 0
}
######################################################
# Install or upgrade codeql environment.
######################################################
function install_upgrade_codeql_tool
{
  if [[ ! -e ${tool_path} ]]; then
    mkdir -p ${tool_path}
  fi
  pushd ${tool_path} >> ${log}
  {
    for repo_branch in ${TOOL_GIT_REPO[@]}; do
      local tmp_array=(${repo_branch//:/ })
      local group_name=${tmp_array[0]}
      local repo_name=${tmp_array[1]}
      local branch_name=${tmp_array[2]}
      local commit_id=${tmp_array[3]}
      local repo_url="${TOOL_GIT_URL}/${group_name}/${repo_name}.git"
      echo "[INFO] Clone and update ${repo_name} from ${repo_url}"
      git_clone_update ${repo_url} ${repo_name} ${branch_name} ${commit_id}
      if [[ $? -ne 0 ]]; then
        echo "[ERR ] line:${LINENO} Clone and update ${repo_name} from ${repo_url}"
        return 1
      fi
    done
    
    # TODO
    sed -ir 's/\(sudo add-apt-repository ppa:deadsnakes.*\)/\1 -y/g' ${tool_integ_folder}/exec_codeql_cli.sh
    sed -ir 's/= \(\"\(arene-ivi-appmng-app-mng\|arene-ivi-vehicle-control\)\"\)/=~ \1/g' ${tool_integ_folder}/exec_codeql_cli.sh

    # TODO https://github.tmc-stargate.com/arene-os-services-cockpit-tmc-wa/arene-ivi-misc-integ-integrator/pull/339
    tool_ts_query_path=${tool_path}/${tool_ts_query_folder}
    if [[ ! -e ${tool_ts_query_path} ]]; then
      mkdir ${tool_ts_query_path}
    fi
    pushd ${tool_ts_query_path} >> ${log}
    {
      wget https://artifactory-ha.tmc-stargate.com:443/artifactory/arene-os-services-cockpit-generic-local-private/codeql-ts-query/arene-codeql-deps.tar.xz
      if [[ $? -eq 0 ]]; then
        tar -xvf arene-codeql-deps.tar.xz
      fi
    }
    popd >> ${log} # ${tool_ts_query_path}
  }
  popd >> ${log} # ${tool_path}
}
function install_upgrade_sdk
{
  if [[ -e ${sdk_path} ]]; then
    mkdir -p ${sdk_path}
  fi
  pushd ${sdk_path} >> ${log}
  {
    # check sdk version
    echo "[INFO] Get arene ivi sdk packages version." | tee -a ${log}
    wget -q --show-progress -P list_info ${SDK_URL} 2>&1 | tee -a ${log}
    if [[ $? -ne 0 ]]; then
      echo "[ERR ] line:${LINENO} Filed to get arene ivi sdk packages version." | tee -a ${log}
      rm -fr list_info
      return 1
    fi
    local sdk_file=$(grep 'genericx86-64.sh' list_info/index.html | cut -d \" -f 2 | sort -V | tail -1)
    local sdk_update_date=$(grep 'genericx86-64.sh' list_info/index.html | awk '{print($3,$4)}' | sort -V | tail -1)
    local sdk_version=$(echo ${sdk_file} | cut -d - -f 5)
    rm -rf list_info
    echo "" | tee -a ${log}
    echo "[INFO] Remote arene ivi sdk info [version=${sdk_version}, update_date=${sdk_update_date}]." | tee -a ${log}

    # need upgrade sdk
    if [[ ${sdk_update_date} != ${SDK_UPDATE_DATE} || ${sdk_version} != ${SDK_VERSION} || ! -e ${sdk_folder} ]];then 
      ## delete old sdk
      echo "[INFO] Delete old arene ivi sdk file from local."  | tee -a ${log}
      rm -fr ${sdk_folder}  >> ${log} 2>&1  && rm -fr arene-toolchain-cockpit-ivi-${SDK_VERSION}-genericx86-64.sh  >> ${log} 2>&1
      if [[ $? -ne 0 ]]; then
        echo "[ERR ] line:${LINENO} Failed to delete old arene ivi sdk file from local. "  | tee -a ${log}
        return 1
      fi 

      ## download new sdk
      echo "[INFO] Download new arene ivi sdk install file from remote." | tee -a ${log}
      wget -q ${SDK_URL}/${sdk_file} 2>&1 | tee -a ${log}
      if [[ $? -ne 0 ]]; then
        echo "[ERR ] Filed to download new arene ivi sdk install file from remote." | tee -a ${log}
        rm -fr ${sdk_file}
        return 1
      fi

      ## install new sdk
      local docker_sdk_path=$(echo /workdir/${sdk_path}/${sdk_folder} | sed "s@/${WORK_PATH}@@g")
      echo "[INFO] Install new arene ivi sdk."  | tee -a ${log}
      docker run --rm -v ~:/home/hosthome:ro -v ${WORK_PATH}:/workdir --name poky-$(id -un)-arene_codeql \
        --workdir=/workdir ${CODEQL_DOCKER_IMAGE_REPOSITORY}:${CODEQL_DOCKER_IMAGE_TAG} \
          bash -c " pwd; \
            bash ./${sdk_file} -y -d ${docker_sdk_path}; \
            chown -R ${user_uid}:${user_gid} ${docker_sdk_path}; \
            exit" >> ${log} 2>&1
      if [[ $?  -ne 0 ]]; then
        echo "[ERR ] line:${LINENO} Failed to install new sdk. sdk install file=>${sdk_file}" | tee -a ${log}
        return 1
      fi

      ## update sdk info to config file
      sed -ri "s/(^SDK_VERSION)=.*$/\1=\'${sdk_version}\'/g"  ${cfg_file}
      sed -ri "s/(^SDK_UPDATE_DATE)=.*$/\1=\'${sdk_update_date}\'/g"  ${cfg_file}

      ## Backup the new build sdk installation file. 
      local sdk_backup_path="${backup_sdk_path}/${sdk_version}_${sdk_update_date// /-}"
      echo "[INFO] Backup the new arene ivi sdk installation file to backup_path=>${sdk_backup_path}" | tee -a ${log}
      if [[ ! -e ${sdk_backup_path} ]]; then
        mkdir -p ${sdk_backup_path}
      fi
      cp -fr ${sdk_file} ${sdk_backup_path}
      if [[ $?  -ne 0 ]]; then
        echo "[ERR ] line:${LINENO} Failed to backup the new arene ivi sdk installation file to backup_path=>${sdk_backup_path}" | tee -a ${log}
        return 1
      fi
    fi
  }
  popd >> ${log} #${sdk_path} 

  return 0
}
function install_upgrade_env
{
  # install sdk
  echo "[INFO] Start install or upgrade sdk."   | tee -a ${log}
  install_upgrade_sdk
  if [[ $? -ne 0 ]]; then
    echo "[ERR ] line:${LINENO} Failed to install or upgrade sdk." | tee -a ${log}
    return 1
  fi
  echo "[INFO] Successfully install or upgrade sdk." | tee -a ${log}
  echo ""      | tee -a ${log}


  # install codeql tool
  echo "[INFO] Start install or upgrade codeql tool."   | tee -a ${log}
  install_upgrade_codeql_tool
  if [[ $? -ne 0 ]]; then
    echo "[ERR ] line:${LINENO} Failed to install or upgrade codeql tool." | tee -a ${log}
    return 1
  fi
  echo "[INFO] Successfully install or upgrade codeql tool." | tee -a ${log}
  echo ""      | tee -a ${log}
  return 0
}

######################################################
# Update codeql target source code.
######################################################
function update_codeql_target
{
  if [[ ! -e ${input_path} ]]; then
    mkdir -p ${input_path}
  fi
  pushd ${input_path} >> ${log}
  {
    for repo_branch in ${CODEQL_TARGET_GIT_REPO[@]}; do
      local tmp_array=(${repo_branch//:/ })
      local group_name=${tmp_array[0]}
      local repo_name=${tmp_array[1]}
      local branch_name=${tmp_array[2]}
      local commit_id=${tmp_array[3]}
      local repo_url="${CODEQL_TARGET_GIT_URL}/${group_name}/${repo_name}.git"
      echo "[INFO] Clone and update ${repo_name} from ${repo_url}"
      git_clone_update ${repo_url} ${repo_name} ${branch_name} ${commit_id}
      if [[ $? -ne 0 ]]; then
        echo "[ERR ] line:${LINENO} Failed to clone and update ${repo_name} from ${repo_url}"
        return 1
      fi

      # update submodule
      local tmp_sub_repo_info=${CODEQL_TARGET_GIT_SUB_REPO[${repo_name}]}
      if [[ -n ${tmp_sub_repo_info} ]]; then
        local tmp_sub_repo_info_array=(${tmp_sub_repo_info//:/ })
        local sub_repo_group=${tmp_sub_repo_info_array[0]}
        local sub_repo_name=${tmp_sub_repo_info_array[1]}
        local sub_repo_branch=${tmp_sub_repo_info_array[2]}
        local sub_repo_url="${CODEQL_TARGET_GIT_URL}/${sub_repo_group}/${sub_repo_name}.git"
        echo "[INFO] Add and update submodule ${sub_repo_name} from ${sub_repo_url}"
        git_submodule_update ${repo_name} ${sub_repo_url} ${sub_repo_name} ${sub_repo_branch} 
        if [[ $? -ne 0 ]]; then
          echo "[ERR ] line:${LINENO} Failed to add and update submodule ${sub_repo_name} from ${sub_repo_url}"
          return 1
        fi
      fi
    done
  }
  popd >> ${log} # ${input_path}
}

######################################################
# Execute codeql checking and parsing. 
######################################################
function codeql_check_parse
{
  local repo_unit_list=()
  local index=0
  echo "[INFO] Please select the repo and unit to check." | tee -a ${log}
  echo "------------------------------------------------" | tee -a ${log}
  for repo in ${!CODEQL_TARGET_GIT_REPO_UNITS[@]}; do
    echo $repo
    local repo_abs_path=${input_path}/${repo}
    if [[ -e ${repo_abs_path} ]]; then 
      local unit_list=(${CODEQL_TARGET_GIT_REPO_UNITS[${repo}]})
      for unit in ${unit_list[@]}; do
        if [[ ${unit} == "none" || -e ${repo_abs_path}/${unit} ]]; then
          repo_unit_list[${index}]="${repo}:${unit}"
          # echo "${index}    ${repo_unit_list[${index}]}"  | tee -a ${log}
          printf "%-8s%-100s\n" ${index} ${repo_unit_list[${index}]}  | tee -a ${log}
          index=$((index+1))
        fi
      done
    fi
  done
  repo_unit_list[${index}]="exit"
  # echo "${index}    exit codeql checking and parsing."    | tee -a ${log}
  printf "%-8s%-100s\n" ${index} "exit codeql checking and parsing." | tee -a ${log}
  echo "------------------------------------------------" | tee -a ${log}
  read -p "[INFO] Please enter the repo and unit number for executing codeql:" number
  if [[ ${number} -ge ${index} ]];then
    return 0
  fi

  local repo_unit=${repo_unit_list[${number}]}
  local docker_repo=${repo_unit%%:*}
  local docker_unit=${repo_unit##*:}
  local docker_repo_path="$(echo ${input_path}| sed "s@${WORK_PATH}/@@g")/${docker_repo}"
  local docker_repo_abs_path="/workdir/${docker_repo_path}"

  local docker_sdk_path=$(echo /workdir/${sdk_path}/${sdk_folder} | sed "s@/${WORK_PATH}@@g")
  local docker_tool_path=$(echo /workdir/${tool_path} | sed "s@/${WORK_PATH}@@g")
  local docker_output_path=$(echo /workdir/${output_path} | sed "s@/${WORK_PATH}@@g")
  local docker_log_path=$(echo /workdir/${log_path} | sed "s@/${WORK_PATH}@@g")
  local docker_backup_codeql_path=$(echo /workdir/${backup_codeql_path} | sed "s@/${WORK_PATH}@@g")

  # codeql
  echo "[INFO] Start executing the codeql of the repo [${number}  ${repo_unit}]." | tee -a ${log}
  docker run --rm -v ~:/home/hosthome:ro -v ${WORK_PATH}:/workdir --name poky-$(id -un)-arene_codeql \
    -e CODEQL_WORK_DIR="/workdir" -e OUTPUT_CODEQL_DIR=${docker_output_path} -e COMPONENT=${docker_repo_path} -e UNIT=${docker_unit}\
    -e QUERY_RELATIVE_PATH="/workdir/codeql-ts-query/deps/codeql_tools/codeql" \
    -e QUERY_ABSOLUTE_PATH="/workdir/codeql-ts-query/deps/codeql_tools/codeql" \
    --workdir=/workdir ${CODEQL_DOCKER_IMAGE_REPOSITORY}:${CODEQL_DOCKER_IMAGE_TAG} \
      bash -c "docker_log_file=${docker_log_path}/${docker_repo}_${docker_unit}_\$(date +%Y%m%d%H%M%S).log; \
        python -m pip install --upgrade pip ; \
        pwd >\${docker_log_file} 2>&1;\
        source ${docker_sdk_path}/environment-setup-core2-64-arene-linux >>\${docker_log_file} 2>&1; \
        pushd ${docker_tool_path}/${tool_integ_folder} >>\${docker_log_file} 2>&1;\
          if [ ! -d /usr/local/bin/codeql ]; then \
            sed -i '/sudo tar xf codeql-bundle-linux64.tar.gz/a\    cp -fr /usr/local/bin/codeql-bundle-linux64.tar.gz /workdir/backup'  setup_codeql_cli.sh; \
            source setup_codeql_cli.sh >>\${docker_log_file} 2>&1; \
            sed -i '/sudo tar xf codeql-bundle-linux64.tar.gz/{n; d}' setup_codeql_cli.sh; \
            chown ${user_uid}:${user_gid} /workdir/backup/codeql-bundle-linux64.tar.gz; \
          fi; \
          bash ./exec_codeql_analysis_for_local.sh >>\${docker_log_file} 2>&1 || exit 1;  \
        popd >>\${docker_log_file} ; \
        echo 'get repo info.' >>\${docker_log_file}; \
        pushd ${docker_repo_abs_path} >>\${docker_log_file}; \
          branch=\$(git rev-parse --abbrev-ref HEAD); \
          commitid=\$(git rev-parse HEAD); \
        popd >> \${docker_log_file}; \
        echo 'modify output folder name and backup' >>\${docker_log_file}; \
        pushd ${docker_output_path}/output_codeql_analysis >>\${docker_log_file}; \
          docker_backup_codeql_sub_path=${docker_backup_codeql_path}/${docker_repo}/\${branch}/\${commitid};\
          if [[ ! -e \${docker_backup_codeql_sub_path} ]];then \
            mkdir -p \${docker_backup_codeql_sub_path}; \
          fi; \
          output_folder_name=\$(ls ./ | grep -E  '^[0-9]{4}.*' | tail -1) ; \
          if [[ \${output_folder_name} != '' ]];then \
            new_output_folder_name=${docker_repo}_${docker_unit}_\$(date +%Y%m%d%H%M%S) ; \
            tar_file_name=${docker_repo}_${docker_unit}_\$(date +%Y%m%d%H%M%S).tar.gz ; \
            mv \${output_folder_name} \${new_output_folder_name}; \
            tar -zcf \${tar_file_name} \${new_output_folder_name}; >> \${docker_log_file} 2>&1; \
            mv -f \${tar_file_name} \${docker_backup_codeql_sub_path}; \
            echo -e 'repo message:\n branch='\${branch}'\n commitid='\${commitid}'\n' > \${new_output_folder_name}/repo_info.txt ;\
          fi; \
        popd >> \${docker_log_file} ; \
        echo 'Record the mapping of codeql results and repo'>>\${docker_log_file}; \
        echo '=============================================' >>\${docker_log_file}; \
        echo [INFO] The mapping of codeql results and repo >>\${docker_log_file}; \
        echo [INFO] repo=[${docker_repo}],banch=[\${branch}],commitid=[\${commitid}]>>\${docker_log_file}; \
        echo [INFO] codeql resule: \${tar_file_name} >>\${docker_log_file}; \
        echo '=============================================' >>\${docker_log_file}; \
        echo 'Reset codeql environment.' >>\${docker_log_file}; \
        chown ${user_uid}:${user_gid} \${docker_log_file}; \
        cp -fr \${docker_log_file} \${docker_backup_codeql_sub_path}; \
        chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_integ_folder}; \
        chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_query_folder}; \
        chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_ts_query_folder}; \
        chown -R ${user_uid}:${user_gid} ${docker_repo_abs_path}; \
        chown -R ${user_uid}:${user_gid} ${docker_output_path}; \
        chown -R ${user_uid}:${user_gid} ${docker_backup_codeql_path}; \
        exit" >> ${log} 2>&1
  if [[ $?  -ne 0 ]]; then
    echo "[ERR ] Failed to executing the codeql of the repo [${repo_unit}]." | tee -a ${log}
    return 1
  fi
  echo "[INFO] Successfully executing the codeql of the repo [${repo_unit}]." | tee -a ${log}
  return 0
}

function codeql_check_parse_all
{
  local repo_unit_list=()
  local index=0
  echo "[INFO] Please select the repo and unit to check." | tee -a ${log}
  echo "------------------------------------------------" | tee -a ${log}
  for repo in ${!CODEQL_TARGET_GIT_REPO_UNITS[@]}; do
    local repo_abs_path=${input_path}/${repo}
    if [[ -e ${repo_abs_path} ]]; then 
      local unit_list=(${CODEQL_TARGET_GIT_REPO_UNITS[${repo}]})
      if [[ ${#unit_list[*]} -ge 1 && ${unit_list[0]} != "none" ]];then
        repo_unit_list[${index}]="${repo}:${unit_list}"
        # echo "${index}    ${repo}:all"  | tee -a ${log}
        printf "%-8s%-100s\n" ${index} "${repo}:all" | tee -a ${log}
        index=$((index+1))
      fi
      for unit in ${unit_list[@]}; do
        if [[ ${unit} == "none" || -e ${repo_abs_path}/${unit} ]]; then
          repo_unit_list[${index}]="${repo}:${unit}"
          # echo "${index}    ${repo_unit_list[${index}]}"  | tee -a ${log}
          printf "%-8s%-100s\n" ${index} ${repo_unit_list[${index}]} | tee -a ${log}
          index=$((index+1))
        fi
      done
    fi
  done
  repo_unit_list[${index}]="exit"
  # echo "${index}    exit codeql checking and parsing."    | tee -a ${log}
  printf "%-8s%-100s\n" ${index} "exit codeql checking and parsing."  | tee -a ${log}
  echo "------------------------------------------------" | tee -a ${log}
  read -p "[INFO] Please enter the repo and unit number for executing codeql:" number
  if [[ ${number} -ge ${index} ]];then
    return 0
  fi

  local repo_units=${repo_unit_list[${number}]}
  local docker_repo=${repo_units%%:*}
  local docker_units=(${repo_units##*:})
  local docker_repo_path="$(echo ${input_path}| sed "s@${WORK_PATH}/@@g")/${docker_repo}"
  local docker_repo_abs_path="/workdir/${docker_repo_path}"

  local docker_sdk_path=$(echo /workdir/${sdk_path}/${sdk_folder} | sed "s@/${WORK_PATH}@@g")
  local docker_tool_path=$(echo /workdir/${tool_path} | sed "s@/${WORK_PATH}@@g")
  local docker_output_path=$(echo /workdir/${output_path} | sed "s@/${WORK_PATH}@@g")
  local docker_log_path=$(echo /workdir/${log_path} | sed "s@/${WORK_PATH}@@g")
  local docker_backup_codeql_path=$(echo /workdir/${backup_codeql_path} | sed "s@/${WORK_PATH}@@g")
  if [[ ! -e ${output_path} ]]; then
    mkdir -p ${output_path}
  fi

  # codeql
  echo "[INFO] Start executing the codeql of the repo [${number}  ${repo_units}]." | tee -a ${log}
  docker run --rm -v ~:/home/hosthome:ro -v ${WORK_PATH}:/workdir --name poky-$(id -un)-arene_codeql \
    -e CODEQL_WORK_DIR="/workdir" -e OUTPUT_CODEQL_DIR=${docker_output_path} -e COMPONENT=${docker_repo_path} -e UNITS=${docker_units}\
    --workdir=/workdir ${CODEQL_DOCKER_IMAGE_REPOSITORY}:${CODEQL_DOCKER_IMAGE_TAG} \
      bash -c "for unit in \${UNITS}; do \
          docker_log_file=${docker_log_path}/${docker_repo}_\${unit}_\$(date +%Y%m%d%H%M%S).log; \
          pwd >\${docker_log_file}; \
          source ${docker_sdk_path}/environment-setup-core2-64-arene-linux >>\${docker_log_file} 2>&1; \
          export UNIT=\${unit}; \
          echo 'Start executing codeql.' >>\${docker_log_file}; \
          pushd ${docker_tool_path}/${tool_integ_folder} >>\${docker_log_file} ;\
            if [ ! -d /usr/local/bin/codeql ]; then \
              sed -i '/sudo tar xf codeql-bundle-linux64.tar.gz/a\    cp -fr /usr/local/bin/codeql-bundle-linux64.tar.gz /workdir/backup'  setup_codeql_cli.sh; \
              source setup_codeql_cli.sh >>\${docker_log_file} 2>&1; \
              chown ${user_uid}:${user_gid} /workdir/backup/codeql-bundle-linux64.tar.gz; \
              sed -i '/sudo tar xf codeql-bundle-linux64.tar.gz/{n; d}' setup_codeql_cli.sh; \
            fi; \
            bash ./exec_codeql_analysis_for_local.sh >>\${docker_log_file} 2>&1 || exit 1;  \
          popd >>\${docker_log_file} ; \
          echo 'get repo info.' >>\${docker_log_file}; \
          pushd ${docker_repo_abs_path} >>\${docker_log_file}; \
            branch=\$(git rev-parse --abbrev-ref HEAD); \
            commitid=\$(git rev-parse HEAD); \
          popd >> \${docker_log_file}; \
          echo 'modify output folder name and backup' >>\${docker_log_file}; \
          pushd ${docker_output_path}/output_codeql_analysis >>\${docker_log_file}; \
            docker_backup_codeql_sub_path=${docker_backup_codeql_path}/${docker_repo}/\${branch}/\${commitid};\
            if [[ ! -e \${docker_backup_codeql_sub_path} ]];then \
              mkdir -p \${docker_backup_codeql_sub_path}; \
            fi; \
            output_folder_name=\$(ls ./ | grep -E  '^[0-9]{4}.*' | tail -1) ; \
            if [[ \${output_folder_name} != '' ]];then \
              new_output_folder_name=${docker_repo}_\${unit}_\$(date +%Y%m%d%H%M%S) ; \
              tar_file_name=${docker_repo}_\${unit}_\$(date +%Y%m%d%H%M%S).tar.gz ; \
              mv \${output_folder_name} \${new_output_folder_name}; \
              tar -zcf \${tar_file_name} \${new_output_folder_name}; >> \${docker_log_file} 2>&1; \
              mv -f \${tar_file_name} \${docker_backup_codeql_sub_path}; \
            fi; \
          popd >> \${docker_log_file} ; \
          echo 'Record the mapping of codeql results and repo'>>\${docker_log_file}; \
          echo '=============================================' >>\${docker_log_file}; \
          echo [INFO] The mapping of codeql results and repo >>\${docker_log_file}; \
          echo [INFO] repo=[${docker_repo}],banch=[\${branch}],commitid=[\${commitid}]>>\${docker_log_file}; \
          echo [INFO] codeql resule: \${tar_file_name} >>\${docker_log_file}; \
          echo '=============================================' >>\${docker_log_file}; \
          echo 'Reset codeql environment.' >>\${docker_log_file}; \
          chown ${user_uid}:${user_gid} \${docker_log_file}; \
          cp -fr \${docker_log_file} \${docker_backup_codeql_sub_path}; \
          chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_integ_folder}; \
          chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_query_folder}; \
          chown -R ${user_uid}:${user_gid} ${docker_tool_path}/${tool_ts_query_folder}; \
          chown -R ${user_uid}:${user_gid} ${docker_repo_abs_path}; \
          chown -R ${user_uid}:${user_gid} ${docker_output_path}; \
          chown -R ${user_uid}:${user_gid} ${docker_backup_codeql_path}; \
        done ;\
        exit" >> ${log} 2>&1
  if [[ $?  -ne 0 ]]; then
    echo "[ERR ] line:${LINENO} Failed to executing the codeql of the repo [${repo_units}]." | tee -a ${log}
    return 1
  fi
  echo "[INFO] Successfully executing the codeql of the repo [${repo_units}]." | tee -a ${log}
  return 0
}

######################################################
# main function
######################################################
trap "on_ctrl_c" SIGINT
trap "on_abnormal_exit" SIGHUP
start_execute
while true ;do
  echo "#####################################################################"
  echo "#         Please select one of the options below to proceed         #"
  echo "# Options:                                                          #"
  echo "#         1   Install or upgrade codeql environment.                #"
  echo "#         2   Update codeql target source code.                     #"
  echo "#         3   Execute codeql checking and parsing.                  #"
  # echo "#         4   Execute codeql checking and parsing(for repo group).  #"
  echo "#         0   exit                                                  #"
  echo "#####################################################################"
  source ${cfg_file}
  read -p "Please enter your options or Ctrl-c to cancel it:" options
  echo ""
  case ${options} in
    1)
      pushd ${WORK_PATH} >> ${log}
      {
        echo "======================================================"    | tee -a ${log}
        echo "[INFO] Start install or upgrade codeql environment."       | tee -a ${log}
        time install_upgrade_env
        if [[ $? -ne 0 ]];then
          echo "[ERR ] Failed to install or upgrade codeql environment." | tee -a ${log}
          echo "======================================================"  | tee -a ${log}
        else
          echo "[INFO] Successfully install or upgrade codeql environment." | tee -a ${log}
          echo "======================================================"     | tee -a ${log}
        fi
        echo ""                                                           | tee -a ${log}
      }
      popd >> ${log} #${WORK_PATH}
      ;;
    2)
      pushd ${WORK_PATH} >> ${log}
      {
        echo "======================================================"    | tee -a ${log}
        echo "[INFO] Start update codeql target source code."            | tee -a ${log}
        time update_codeql_target
        if [[ $? -ne 0 ]];then
          echo "[ERR ] Failed to update codeql target source code."      | tee -a ${log}
          echo "======================================================"  | tee -a ${log}
        else
          echo "[INFO] Successfully update codeql target source code."     | tee -a ${log}
          echo "======================================================"    | tee -a ${log}
        fi
        echo ""                                                          | tee -a ${log}
      }
      popd >> ${log} #${WORK_PATH}
      ;;
    3)
      pushd ${WORK_PATH} >> ${log}
      {
        echo "======================================================"    | tee -a ${log}
        echo "[INFO] Start execute codeql checking and parsing."         | tee -a ${log}
        time codeql_check_parse
        if [[ $? -ne 0 ]];then
          echo "[ERR ] Failed to execute codeql checking and parsing."   | tee -a ${log}
          echo "======================================================"  | tee -a ${log}
        else
          echo "[INFO] Successfully execute codeql checking and parsing."   | tee -a ${log}
          echo "======================================================"     | tee -a ${log}
        fi
        echo ""                                                           | tee -a ${log}
      }
      popd >> ${log} #${WORK_PATH}
      ;;
    4)
      pushd ${WORK_PATH} >> ${log}
      {
        echo "======================================================"    | tee -a ${log}
        echo "[INFO] Start execute codeql checking and parsing."         | tee -a ${log}
        time codeql_check_parse_all
        if [[ $? -ne 0 ]];then
          echo "[ERR ] Failed to execute codeql checking and parsing."   | tee -a ${log}
          echo "======================================================"  | tee -a ${log}
        else
          echo "[INFO] Successfully execute codeql checking and parsing."   | tee -a ${log}
          echo "======================================================"     | tee -a ${log}
        fi
        echo ""                                                           | tee -a ${log}
      }
      popd >> ${log} #${WORK_PATH}
      ;;
    0)
      pushd ${WORK_PATH} >> ${log}
      {
        finish
      }
      popd >> ${log} #${WORK_PATH}
      ;;
    *)
      echo "[ERROR ] ------wrong option = [ ${options} ]!!!------" 
      ;;
  esac
done
exit 0
